﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Minecraft_2D.Blocks;

namespace Minecraft_2D
{
    public class Block
    {
        #region Attributs
        private TypeBloc _type;
        private Bloc _bloc;
        private Block _top;
        private Block _bottom;
        private Block _left;
        private Block _right;
        private Point _position;
        private static Map _map;
        #endregion

        #region Constructeur
        public Block()
        {
            _top = null;
            _bottom = null;
            _left = null;
            _right = null;
            _type = TypeBloc.Air;
            _bloc = BlocSet.GetSingleton()[Type];
        }
        #endregion

        #region Proprietés
        public TypeBloc Type
        {
            get { return this._type; }
            set
            {
                this._type = value;
                if (_bloc.Id != (int)Type)
                    _bloc = BlocSet.GetSingleton()[Type];
            }
        }

        internal Bloc Bloc
        {
            get { return _bloc; }
            set
            {
                _bloc = value;
                if (Type != (TypeBloc)_bloc.Id)
                    Type = (TypeBloc)_bloc.Id;
            }
        }

        public Block Bottom
        {
            get { return _bottom; }
            set { _bottom = value; }
        }

        public Block Left
        {
            get { return _left; }
            set { _left = value; }
        }

        public Block Right
        {
            get { return _right; }
            set { _right = value; }
        }

        public Block Top
        {
            get { return this._top; }
            set { this._top = value; }
        }

        public Point Position
        {
            get { return this._position; }
            set { this._position = value; }
        }

        public static Map Map
        {
            get { return Block._map; }
            set { Block._map = value; }
        }
        #endregion

        #region Methodes

        public Point Contient(int r, TypeBloc type)
        {
            while (r >= 0)
            {
                Point p = Cercle(this, r--, type);
                if (!p.IsEmpty)
                    return p;
            }
            return new Point();
        }

        public static Point Cercle(Block b, int r, TypeBloc bloc)
        {
            if (r < 0)
                return new Point();

            int x = 0;
            int y = r;
            int d = r - 1;

            while (y >= x)
            {
                Point p;
                p = new Point(x + b.Position.X, y + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;

                p = new Point(y + b.Position.X, x + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;

                p = new Point(-x + b.Position.X, y + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;

                p = new Point(-y + b.Position.X, x + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;

                p = new Point(x + b.Position.X, -y + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;

                p = new Point(y + b.Position.X, -x + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;

                p = new Point(-x + b.Position.X, -y + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;

                p = new Point(-y + b.Position.X, -x + b.Position.Y);
                if (p.X >= 0 && p.Y >= 0 && p.X < Block.Map.Height && p.Y < Block.Map.Length)
                    if (Block.Map[p].Type == bloc)
                        return p;


                if (d >= 2 * (x - 1))
                {
                    d -= 2 * x;
                    x++;
                }
                else if (d <= 2 * (r - y))
                {
                    d += 2 * y - 1;
                    y--;
                }
                else
                {
                    d += 2 * (y - x - 1);
                    y--;
                    x++;
                }
            }
            return new Point();
        }

        public override string ToString()
        {
            return "{" + Type.ToString() + ", " + Position.ToString() + "}";
        }
        #endregion

        #region Cast
        public static implicit operator TypeBloc(Block b)
        {
            return b.Type;
        }
        #endregion
    }
}
